// EncodingStream.cpp : Implementation of CEncodingStream
#include "stdafx.h"
#include "Base64.h"
#include "EncodingStream.h"

/////////////////////////////////////////////////////////////////////////////
// CEncodingStream

STDMETHODIMP CEncodingStream::InterfaceSupportsErrorInfo(REFIID riid)
{
	static const IID* arr[] = 
	{
		&IID_IDecodingStream
	};
	for (int i=0; i < sizeof(arr) / sizeof(arr[0]); i++)
	{
		if (::InlineIsEqualGUID(*arr[i],riid))
			return S_OK;
	}
	return S_FALSE;
}

STDMETHODIMP CEncodingStream::open(BSTR sFileName,BOOL bWriteWideChars)
{
	HRESULT hr = E_NOTIMPL;
	//TODO: error handling
	IStream * pStream = 0;
	if(sFileName)
	{
		IStorage * pStorage;
		//open a target file stream
		hr = StgCreateDocfile(sFileName,STGM_WRITE,0,&pStorage);
		if(SUCCEEDED(hr))
		{
			hr = pStorage->CreateStream(sFileName, STGM_WRITE, 0, 0, &pStream);
			pStorage->Release();
		}
	}
	else
	{
		//open a stream in memory
		hr = CreateStreamOnHGlobal(NULL,TRUE,&pStream);
		
	}

	if(SUCCEEDED(hr) && pStream)
	{
		m_Encoder.put_stream(pStream);
		pStream->Release();
	}
	

	m_Encoder.m_bWideOutput = bWriteWideChars != 0;
	
	return hr;
}

STDMETHODIMP CEncodingStream::Read( void *pv,ULONG cb,ULONG *pcbRead)
{
	return m_Encoder.Read(pv,cb,pcbRead);

}

STDMETHODIMP CEncodingStream::Write(const void *pv,ULONG cb,ULONG *pcbWritten)
{
	HRESULT hr;
	if(cb)
	{
		hr = S_OK;
		// cast the input as a byte stream
		const char * pc = static_cast<const char *>(pv);

		//loop through and encode the input bytes.
		for(unsigned int i = 0;i < cb; ++i)
		{
			m_Encoder.putc(pc[i]);
		}
		
		//TODO: return the actual count written.
		*pcbWritten = cb;
	}
	else
	{
		//user is trying to write nothing to the stream, 
		//	does nothing.
		hr = S_FALSE;
	}
	return hr;
}
